package com.competition.web.admin.task.run;

import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;

import com.admin.param.contract.IQueryEligibleEnterprisesRequestParm;
import com.admin.vo.CompanyInfoVO;
import com.admin.vo.contract.ICompanyInfoVO;
import com.common.util.PositionUtil;
import com.competition.param.impl.VisitRequestParam;
import com.competition.web.admin.config.HttpRequest;
import com.competition.web.constant.RedisConstant;
import com.competition.web.entity.GeoCodes;
import com.competition.web.entity.GeoRegeo;
import com.competition.web.entity.GeoRegeoPlanning;
import com.competition.web.entity.GeoRoute;
import com.competition.web.entity.GeoTransits;
import com.competition.web.entity.IGeoRoute;
import com.competition.web.entity.IPlanByRoute;
import com.unify.type.Data;
import com.unify.type.ExploringHorsesResponse;
import com.unify.type.IExploringHorsesResponse;
import com.unify.type.SearchColumn;
import com.unify.type.SearchColumn.Option;
import com.unify.type.WalkPaths;
import com.unify.type.WalkPlan;

/**
 * 处理符合条件的企业
 */
public class HandlingEligibleEnterprises<VO extends ICompanyInfoVO> implements Runnable {

	private static Logger LOGGER = LoggerFactory.getLogger(HandlingEligibleEnterprises.class);

	private List<VO> vos;

	RedisTemplate<String, ICompanyInfoVO> redisTemplate;

	private HttpRequest httpRequest;

	private int numberOfRequestedCoordinates;

	private String token;

	private IQueryEligibleEnterprisesRequestParm<?> eligibleEnterprisesRequestParm;

	private Integer commutingHours;

	/**
	 * 成年人走一公里走的时间（秒）
	 */
	private Integer TIME_TO_TRAVEL_ONE_KILOMETER = 900;

	// 锚点企业
	private VO anchorEnterprise;

	public HandlingEligibleEnterprises(List<VO> vos, RedisTemplate<String, ICompanyInfoVO> redisTemplate,
			HttpRequest httpRequest, IQueryEligibleEnterprisesRequestParm<?> eligibleEnterprisesRequestParm, String token,
			VO anchorEnterprise, Integer time) {

		this.redisTemplate = redisTemplate;

		this.httpRequest = httpRequest;

		this.vos = vos;

		this.token = token;

		this.eligibleEnterprisesRequestParm = eligibleEnterprisesRequestParm;

		this.anchorEnterprise = anchorEnterprise;

		this.commutingHours = time;
	}

	@Override
	public void run() {

		Double latitude;

		int i = 0;
		
		HashOperations<String, String, ICompanyInfoVO> opsHash = redisTemplate.opsForHash();

		for (VO vo : vos) {

			latitude = vo.getLatitude();

			if (null != latitude) {
				continue;
			}
			
			obtainEnterpriseLongitudeAndLatitude(vo, opsHash);

			i++;
		}

		int time = 0;

		long currentTimeMillis = System.currentTimeMillis();

		try {

			for (;;) {

				if (i == numberOfRequestedCoordinates) {
					break;
				}

				Thread.sleep(1500);

				if (8000 < time) {
					// 超过27秒
					LOGGER.debug("业已超时， i: {}, number: {}, time: {}", i, numberOfRequestedCoordinates,
							System.currentTimeMillis() - currentTimeMillis);
					return;
				}

				time += 1500;

			}
		} catch (Exception e) {

			e.printStackTrace();
		}

		String companyName = anchorEnterprise.getCompanyName();

		// ----------------------------------------------------

		

		String key = RedisConstant.getEligibleKey(token);

		// 先清理掉数据
//		redisTemplate.delete(key);

		// 获取各个企业与锚点企业的距离

		ParameterizedTypeReference<GeoRegeoPlanning<GeoRoute<GeoTransits>>> parameterizedTypeReferenceByGeoRegeo;
		ParameterizedTypeReference<GeoRegeoPlanning<WalkPlan<WalkPaths>>> parameterizedTypeReferenceByWalking;
		
		ListOperations<String, ICompanyInfoVO> opsForList = redisTemplate.opsForList();

		for (VO vo : vos) {
			// 请求公交路径规划

			final Double distance = PositionUtil.getDistanceByGD(anchorEnterprise.getLongitude(),
					anchorEnterprise.getLatitude(), vo.getLongitude(), vo.getLatitude());

			final String originLocation = anchorEnterprise.getLongitude() + "," + anchorEnterprise.getLatitude();

			final String destination = vo.getLongitude() + "," + vo.getLatitude();
			
			if (600000 < distance) { // 基本上不在本市内了 60KM
				
				LOGGER.debug("vo: {}", vo);
				
				continue;
			}

			/**
			 * 900 3600 成年人走一公里走的时间（秒） < 距离目标企业 时间
			 */
			if (distance <= 1000.000000) {

				if (TIME_TO_TRAVEL_ONE_KILOMETER > commutingHours) {

					continue;
				}

				// 使用步行

				parameterizedTypeReferenceByWalking = new ParameterizedTypeReference<GeoRegeoPlanning<WalkPlan<WalkPaths>>>() {
				};
				this.httpRequest.getWalking(originLocation, destination, parameterizedTypeReferenceByWalking, t -> {

					GeoRegeoPlanning<WalkPlan<WalkPaths>> geoRoute = t.getBody();

					parsePlanTime(vo, geoRoute, opsForList, companyName, originLocation, destination, key, distance);

				});
				continue;
			}
			// 使用公交
			parameterizedTypeReferenceByGeoRegeo = new ParameterizedTypeReference<GeoRegeoPlanning<GeoRoute<GeoTransits>>>() {
			};

			this.httpRequest.getBusRoutePlanning(originLocation, destination, anchorEnterprise.getCity(), vo.getCity(),
					parameterizedTypeReferenceByGeoRegeo, (t) -> {

						GeoRegeoPlanning<GeoRoute<GeoTransits>> body = t.getBody();

						parsePlanTime(vo, body, opsForList, companyName, originLocation, destination, key, distance);

					});

		}

	}

	/**
	 * 处理规划所需要的时间
	 * 
	 * @param <Geo>
	 * @param <T>
	 * @param vo
	 * @param geoRoute
	 * @param opsForList
	 * @param companyName
	 * @param originLocation
	 * @param destination
	 * @param key
	 * @param distance
	 */
	private <Geo extends IGeoRoute, T extends IPlanByRoute<Geo>> void parsePlanTime(VO vo, GeoRegeoPlanning<T> geoRoute,
			ListOperations<String, ICompanyInfoVO> opsForList, String companyName, String originLocation,
			String destination, String key, Double distance) {

		if (1 != geoRoute.getStatus()) {
			LOGGER.debug("起点：{}， 终点：{}, 距离：{}", originLocation, destination, distance);
			LOGGER.debug("msg: {}, status:{}", geoRoute.getInfo(), geoRoute.getStatus());
			return;
		}

		Integer count = geoRoute.getCount();

		if (null == count || 0 == count) {

			vo.setStatus((byte) 0);

			LOGGER.debug("路径规划有{}条, 公司:{}， 坐标：{}，地址：{}\n; 目标公司：{}及地址：{} 坐标：{}, 距离：{}", count, companyName,
					originLocation, anchorEnterprise.getCompanyAddress(), vo.getCompanyName(), vo.getCompanyAddress(),
					destination, distance);

//			if (isNoon) {
//				hashOperations.put(noonKey, "hash-" + clientId + "-" + id, visit);
//
//				return;
//			}

			vo.setDuration(0);

//			opsForList.rightPush(key, vo);

			return;
		}

		T route = geoRoute.getRoute();

		List<Geo> geoTransits = route.getTransits();
		// 默认取第一个

		Geo geoTransit = geoTransits.get(0);

		vo.setStatus((byte) 1);

		Integer duration = geoTransit.getDuration();
		LOGGER.debug(
				"路径规划有{}条, 公司:{}， 坐标：{}，地址：{}\n; 目标公司：{}及地址：{} 坐标：{}, \n距离：{}, duration:{}",
				count, companyName,
				originLocation, anchorEnterprise.getCompanyAddress(), vo.getCompanyName(), vo.getCompanyAddress(),
				destination, distance, duration);		
		if (duration > commutingHours) { // 去当前公司的时间 > 距离目标企业 时间
			return;
		}

		vo.setDuration(duration);

		// TODO 筛选时间范围
		opsForList.rightPush(key, vo);

	}

	/**
	 * 获取企业经纬度
	 * 
	 * @param companyInfoVO
	 */
	protected void obtainEnterpriseLongitudeAndLatitude(ICompanyInfoVO companyInfoVO, HashOperations<String, String, ICompanyInfoVO> opsHash) {

		String companyAddress = companyInfoVO.getCompanyAddress();

		
		this.httpRequest.get(companyAddress, companyInfoVO.getCity(), GeoRegeo.class, (ResponseEntity<GeoRegeo> t) -> {

			GeoRegeo geoRegeo = t.getBody();
			
			if (0 == geoRegeo.getStatus().byteValue()) {
				LOGGER.debug("msg: {}, numberOfRequestedCoordinates: {}", geoRegeo.getInfo(), numberOfRequestedCoordinates);
			}

//			LOGGER.debug("msg: {}, numberOfRequestedCoordinates: {}", geoRegeo.getInfo(), numberOfRequestedCoordinates);
			
			setCompanyData(companyInfoVO, geoRegeo, opsHash);

			numberOfRequestedCoordinates++;
		});

	}

	private void setCompanyData(ICompanyInfoVO companyInfoVO, GeoRegeo geoRegeo, HashOperations<String, String, ICompanyInfoVO> opsHash) {

		if (null == geoRegeo || 0 == geoRegeo.getCount()) {

			LOGGER.debug("公司地址：{}，城市：{}，公司: {}", companyInfoVO.getCompanyAddress(), companyInfoVO.getCity(),
					companyInfoVO.getCompanyName());

			companyInfoVO.setLongitude(0d);

			companyInfoVO.setLatitude(0d);

			companyInfoVO.setStatus((byte) 1);
			return;
		}

		List<GeoCodes> geoCodes = geoRegeo.getGeocodes();

		GeoCodes codes = geoCodes.get(0);

		String[] location = codes.getLocation().split(",");
		

//		LOGGER.debug("getLocation: {}", codes.getLocation());

		companyInfoVO.setLongitude(Double.valueOf(location[0]));

		companyInfoVO.setLatitude(Double.valueOf(location[1]));
		
		opsHash.put(RedisConstant.COMPANY_INFO, companyInfoVO.getId().toString(), companyInfoVO);
	}

}
